package ice.controller;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import ice.Main;
import ice.util.tools;
import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.*;
import javafx.scene.image.Image;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.*;
import javafx.stage.DirectoryChooser;
import org.jsoup.Connection;

import java.io.*;
import java.net.URL;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.ResourceBundle;

/*
 * 作者：icefield
 * 时间：2021/3/22
 * 描述：
 */
public class 单一 implements Initializable {

    @FXML
    private TextField sqlmap路径;

    @FXML
    private TextField 目标url;

    @FXML
    private TextArea 信息框;

    @FXML
    private Button 开始测试按钮;

    @FXML
    private Button 按钮当前库;

    @FXML
    private Button 按钮当前用;

    @FXML
    private Button 按钮数据库;

    @FXML
    private Button 按钮用户;

    @FXML
    private Button 按钮版本;

    @FXML
    private TextField 指定库;

    @FXML
    private Button 按钮库得表;
    @FXML
    private TextField 指定表;

    @FXML
    private Button 按钮表得段;

    @FXML
    private Button 按钮dump表;

    @FXML
    private Button 按钮记录数;

    @FXML
    private TextField 指定段;

    @FXML
    private Button 按钮Dump段;

    @FXML
    private Button 按钮指纹;

    @FXML
    private Button 按钮密码;

    @FXML
    private TextField 用户名;

    @FXML
    private Button 按钮权限;

    @FXML
    private Pane 背景;
    @FXML
    private Pane 背景1;

    @FXML
    private Button 按钮sqlmap路径;

    public static 单一 单一;

    public 单一(){
        单一=this;
    }

    private Connection con = null;

    public Client client=null;

    private JSONArray 信息=null;

    private tools tools = new tools();

    private JSONArray 表名=null;
    private String getvalue=null;
    private HashMap<String,String> uname;

    /*
     *  作者：icefield
     *  说明：初始化单一面板
     */
    @Override
    public void initialize(URL location, ResourceBundle resources) {
        sqlmap路径.setText(Main.main.getSqlmapPath());
        BackgroundImage bg1 = new BackgroundImage(new Image(getClass().getResourceAsStream("/ice/resource/gif2.gif")), BackgroundRepeat.NO_REPEAT, BackgroundRepeat.NO_REPEAT, BackgroundPosition.DEFAULT, BackgroundSize.DEFAULT); //new BackgroundSize(BackgroundSize.AUTO, BackgroundSize.AUTO, false, true, true, true)
        BackgroundImage bg2 = new BackgroundImage(new Image(getClass().getResourceAsStream("/ice/resource/gif3.gif")), BackgroundRepeat.NO_REPEAT, BackgroundRepeat.NO_REPEAT, BackgroundPosition.DEFAULT, new BackgroundSize(BackgroundSize.AUTO, BackgroundSize.AUTO, true, true, true, true)); //new BackgroundSize(BackgroundSize.AUTO, BackgroundSize.AUTO, false, true, true, true)

        背景.setBackground(new Background(bg1));
        背景1.setBackground(new Background(bg2));

    }

    /*
     *  作者：icefield
     *  说明：开始测试按钮点击事件
     */
    @FXML
    void 方法_开始测试(ActionEvent event) {
            updataStatus("开始测试\r\n");

            if(!开始测试按钮.isDisable()) {
                开始测试按钮.setDisable(true);
                按钮当前库.setDisable(true);
                按钮当前用.setDisable(true);
                按钮数据库.setDisable(true);
                按钮用户.setDisable(true);
                按钮版本.setDisable(true);
                按钮库得表.setDisable(true);
                按钮表得段.setDisable(true);
                按钮dump表.setDisable(true);
                按钮记录数.setDisable(true);
                按钮Dump段.setDisable(true);
                按钮指纹.setDisable(true);
                按钮密码.setDisable(true);
                按钮权限.setDisable(true);
                信息=null;
                表名=null;
                new Thread(() -> {
                    try {
                        String url = 目标url.getText();
                        client = new Client(url);
                        String taskid = client.创建任务();
                        if (taskid != "创建错误") {
                            updataStatus("创建任务成功，任务id：" + taskid + "\r\n");
                        }else {
                            updataStatus("创建任务失败！\r\n");
                            开始测试按钮.setDisable(false);
                            return;
                        }
                        Boolean 开始任务 = client.开始任务();
                        if (开始任务) {
                            updataStatus("开始扫描...\r\n");

                        } else {
                            updataStatus("系统异常，开启任务失败\r\n");
                            开始测试按钮.setDisable(false);
                            return;
                        }
                        String 任务状态;
                        String data;
                        long startTime = System.currentTimeMillis();
                        while (开始任务) {
                            任务状态 = client.任务状态();
                            if (任务状态.equals("running")) {
                                updataStatus("#");
                            } else if (任务状态.equals("terminated")) {
                                updataStatus("  扫描完成！\r\n");
                                data = client.任务数据().toJSONString();
                                if (data.length()>2) {
                                    updataStatus("目标URl存在注入漏洞\r\n");
                                    按钮当前库.setDisable(false);
                                    按钮当前用.setDisable(false);
                                    按钮数据库.setDisable(false);
                                    按钮用户.setDisable(false);
                                    按钮版本.setDisable(false);
                                    按钮库得表.setDisable(false);
                                    按钮表得段.setDisable(false);
                                    按钮dump表.setDisable(false);
                                    按钮记录数.setDisable(false);
                                    按钮Dump段.setDisable(false);
                                    按钮指纹.setDisable(false);
                                    按钮密码.setDisable(false);
                                    按钮权限.setDisable(false);
                                }else{
                                    updataStatus("目标URl无法注入\r\n");
                                    client.删除任务();
                                }
                                break;
                            } else {
                                updataStatus("系统异常\r\n");
                                break;
                            }
                            Thread.sleep(1000);
                            if (System.currentTimeMillis()-startTime>90000){
                                updataStatus("扫描目标超时\r\n");
                                if(client.结束任务()){
                                    updataStatus("任务已结束\r\n");
                                }else{
                                    updataStatus("无法结束任务\r\n");
                                }
                                if(client.杀死任务()){
                                    updataStatus("任务已杀死\r\n");
                                }else{
//                                    updataStatus("无法杀死任务\r\n");
                                }
                                break;
                            }
                        }
                        开始测试按钮.setDisable(false);

                    } catch (Exception e) {
//                        e.printStackTrace();
                        updataStatus("系统异常\r\n");
                        开始测试按钮.setDisable(false);
                    }
                }).start();
            }
    }

    @FXML
    void 查看当前库(MouseEvent event) {
        按钮当前库.setDisable(true);
        new Thread(() ->{

                String 开始当前库 = 获取信息(5);
                updataStatus("当前数据库："+开始当前库+"\r\n");
                按钮当前库.setDisable(false);
        }).start();

    }

    @FXML
    void 查看当前用户(MouseEvent event) {
        按钮当前用.setDisable(true);
        new Thread(() ->{

                String 开始当前库 = 获取信息(4);
                updataStatus("当前用户："+开始当前库+"\r\n");
                按钮当前用.setDisable(false);
        }).start();
    }

    @FXML
    void 查看数据库(MouseEvent event) {
        按钮数据库.setDisable(true);
        new Thread(() ->{

                String 开始当前库 = 获取信息(12);
                updataStatus("所有数据库：\r\n\t"+开始当前库+"\r\n");
                按钮数据库.setDisable(false);
        }).start();
    }

    @FXML
    void 查看用户(MouseEvent event) {
        按钮用户.setDisable(true);
        new Thread(() ->{
                String 开始当前库 = 获取信息(8);
                updataStatus("所有用户："+开始当前库+"\r\n");
                按钮用户.setDisable(false);
        }).start();
    }

    @FXML
    void 查看版本(MouseEvent event) {
        按钮版本.setDisable(true);
        new Thread(() ->{
                String 开始当前库 = 获取信息(3);
                updataStatus("数据库版本："+开始当前库+"\r\n");
                按钮版本.setDisable(false);
        }).start();
    }
    @FXML
    void 获取指纹(MouseEvent event) {
        按钮指纹.setDisable(true);
        new Thread(() ->{
            String 开始当前库 = 获取信息(2);
            updataStatus("DBMS指纹：\r\n\t"+开始当前库+"\r\n");
            按钮指纹.setDisable(false);
        }).start();
    }

    public String 获取信息(int type){

        if(信息==null){
            try {
                信息 = client.开始查询();

            } catch (Exception e) {
                e.printStackTrace();
            }
        }
//        JSONArray ar = JSON.parseArray(信息);

        if (信息.size()<2) return "获取失败，当前用户权限不足";
        return tools.getvalue(信息,type);
    }

    @FXML
    void 指定库得表(MouseEvent event) {
//        System.out.println("库得表");
        按钮库得表.setDisable(true);

        new Thread(()->{
            if (表名==null) {
                try {
                    表名 = client.获取表名();
                } catch (Exception e) {
//                    e.printStackTrace();
                    updataStatus("获取表名失败\r\n");
                }
            }
            String db = 指定库.getText().trim();

            String tbs[];
            if(!db.equals("")){

                getvalue = tools.getvalue(表名, 13);
                tbs = tools.从Jo获取(JSONObject.parseObject(getvalue), db);
                if (tbs!=null) {
                    updataStatus("指定数据库【"+db+"】下的表:\t\r\n\t"+tbs[0]+"\r\n");
                }else updataStatus("查无此库\r\n");
            }else{
                getvalue = tools.getvalue(表名, 13);
                tbs = tools.从Jo获取(JSONObject.parseObject(getvalue), db);
                for (int i = 0; i < tbs.length; i++) {
                    String[] s = tbs[i].split(" ");
                    String str = s[0]+":\r\n\t";
                    for (int j = 1; j < s.length; j++) {
                        str+=s[j]+"    ";
                    }
                    str+="\r\n";
                    updataStatus("（"+(i+1)+"）数据库下的所有表名：\r\n\t"+str);
                }
            }
            按钮库得表.setDisable(false);
        }).start();


    }

    @FXML
    void 指定表锝段(MouseEvent event) {
        String db = 指定库.getText().trim();
        String tb = 指定表.getText().trim();
        boolean b = 判断库和表(db, tb);
        if (!b) return;
        try {
            JSONArray ar = client.获取段名(db, tb);
            String value = tools.getvalue(ar, 14);
            String res = JSONObject.parseObject(value).getJSONObject(db).getJSONObject(tb).toJSONString();
            updataStatus("数据库【"+db+"】下的表【"+tb+"】的字段：\r\n\t"+res+"\r\n");

//            System.out.println(getvalue);
        } catch (Exception e) {
            updataStatus("连接超时\r\n");
            e.printStackTrace();
        }

    }

    @FXML
    void dump指定表(MouseEvent event) {
        按钮dump表.setDisable(true);
        new Thread(() -> {

            String db = 指定库.getText().trim();
            String tb = 指定表.getText().trim();
            boolean b = 判断库和表(db, tb);
            if (!b) {
                按钮dump表.setDisable(false);
                return;
            }
            try {
                JSONArray ar = client.dump表(db, tb);
                TableView table = tools.解析表值(ar);
                tools.展示表(table);

//            System.out.println(getvalue);
            } catch (Exception e) {
                updataStatus("连接超时\r\n");
                e.printStackTrace();
            }
            按钮dump表.setDisable(false);
        }).start();


    }

    @FXML
    void dump指定段(MouseEvent event) {
        按钮Dump段.setDisable(true);
        new Thread(() -> {

            String db = 指定库.getText().trim();
            String tb = 指定表.getText().trim();
            String co = 指定段.getText().trim();
            boolean b = 判断库和表(db, tb);
            if (!b) {
                按钮Dump段.setDisable(false);
                return;
            }
            try {
                JSONArray ar = client.dump段(db, tb,co);
                TableView table = tools.解析表值(ar);
                tools.展示表(table);

//            System.out.println(getvalue);
            } catch (Exception e) {
                updataStatus("连接超时\r\n");
                e.printStackTrace();
            }
            按钮Dump段.setDisable(false);
        }).start();
    }

    @FXML
    void 获取记录数(MouseEvent event) {

        String db = 指定库.getText().trim();
        String tb = 指定表.getText().trim();
        boolean b = 判断库和表(db, tb);
        if (!b) return;
        try {
            JSONArray ar = client.获取记录数(db, tb);
            String v = tools.getvalue(ar, 16);
            JSONObject js = JSONObject.parseObject(v);
            JSONObject res = js.getJSONObject(db);
            Iterator<Map.Entry<String, Object>> iterator = res.entrySet().iterator();
            String cou="";
            while (iterator.hasNext()){
                Map.Entry<String, Object> next = iterator.next();
                cou = next.getKey();
            }
            updataStatus("数据库【"+db+"】的表【"+tb+"】记录数量为："+cou+"\r\n");
//            System.out.println(getvalue);
        } catch (Exception e) {
            updataStatus("连接超时\r\n");
            e.printStackTrace();
        }

    }
    @FXML
    void 获取密码(MouseEvent event) {
        按钮密码.setDisable(true);
        new Thread(() ->{
            try {
                updataStatus("这将需要一些时间，请稍后。。。\r\n");
                JSONArray ar = client.获取密码();
                String value = tools.getvalue(ar, 9);
                updataStatus("密码hashes：\r\n\t"+value+"\r\n");
            } catch (Exception e) {
                updataStatus("系统异常\r\n");
                e.printStackTrace();
            }finally {
                按钮密码.setDisable(false);
            }
        }).start();

    }


    @FXML
    void 获取权限(MouseEvent event) {
        按钮权限.setDisable(true);
        new Thread(()->{
            String un = 用户名.getText().trim();
            if (un.equals("")) {
                tools.提醒弹窗("请输入用户名");
                按钮权限.setDisable(false);
                return;
            }
            if (uname==null){
                try {
                    uname=new HashMap<String, String>();
                    JSONArray ar = client.获取权限();
                    String getvalue = tools.getvalue(ar, 10);
                    JSONObject js = JSONObject.parseObject(getvalue);
                    Iterator<Map.Entry<String, Object>> iterator = js.entrySet().iterator();
                    while (iterator.hasNext()){
                        Map.Entry<String, Object> next = iterator.next();
                        uname.put(next.getKey(),next.getValue().toString());
                    }
                    updataStatus("用户【"+un+"】的权限为：\r\n\t"+uname.get(un)+"\r\n");
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }else if(uname.containsKey(un)){
                updataStatus("用户【"+un+"】的权限为：\r\n\t"+uname.get(un)+"\r\n");
            }else{
                tools.提醒弹窗("用户名【"+un+"】不存在");
            }
            按钮权限.setDisable(false);
        }).start();

    }


    @FXML
    void 寻sqlmap路径(MouseEvent event) {
        DirectoryChooser directoryChooser = new DirectoryChooser();
        directoryChooser.setTitle("选择sqlmap路径");
        directoryChooser.setInitialDirectory(new File(System.getProperty("user.home")));

        File sqlmap = directoryChooser.showDialog(Main.stage);
        /*
         *  作者：icefield
         *  说明：若没选择目录，强制退出
         */
        if(null==sqlmap){
            Alert alert = new Alert(Alert.AlertType.WARNING);
            alert.setContentText("请选择Sqlmap主目录");
            alert.showAndWait();
            寻sqlmap路径(event);
        }
        String sqlmapPath = sqlmap.getPath();
        String apipath = sqlmapPath + "/sqlmapapi.py";
        File apiFile = new File(apipath);
        if (!apiFile.exists()){
            Alert al = new Alert(Alert.AlertType.WARNING);
            al.setContentText("选择错误的路径，请重新选择！");
            al.showAndWait();
            寻sqlmap路径(event);
        }
        FileInputStream fileInputStream=null;
        InputStreamReader inputStreamReader=null;
        BufferedReader bufferedReader=null;
        try {
            File jsonFile = new File(System.getProperty("user.home")+"/peizhi.json");
            fileInputStream = new FileInputStream(jsonFile);
            inputStreamReader = new InputStreamReader(fileInputStream, "UTF-8");
            bufferedReader = new BufferedReader(inputStreamReader);
            String tempString=null;
            String readjson="";
            while((tempString=bufferedReader.readLine())!=null){
                readjson+=tempString;
            }
            JSONObject jsonObject = JSONObject.parseObject(readjson);
            jsonObject.put("sqlmapPath",sqlmapPath);
            OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(jsonFile, false), "UTF-8");
            writer.write(jsonObject.toJSONString());
            writer.close();


        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if (fileInputStream!=null) {
                try {
                    fileInputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (inputStreamReader!=null) {
                try {
                    inputStreamReader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (bufferedReader!=null) {
                try {
                    bufferedReader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        Main.sqlmapPath=sqlmap.getPath();
        sqlmap路径.setText(sqlmapPath);
//        String sqlmapPath = sqlmap.getPath();
    }

    public boolean 判断库和表(String db,String tb){
        if(表名==null){
            tools.提醒弹窗("请先点击上面按钮加载指定数据库！");
            return false;
        }
//        String db = 指定库.getText().trim();
//        String tb = 指定表.getText().trim();
        if (tb.equals("") || db.equals("")){
            tools.提醒弹窗("请输入指定的库名和表名");
            return false;
        }
        String [] tbs = tools.从Jo获取(JSONObject.parseObject(getvalue), "");
        boolean flag=false;
        for (int i = 0; i < tbs.length; i++) {
            String[] s = tbs[i].split(" ");
            if (s[0].trim().equals(db)){
                if (tbs[i].indexOf(tb)==-1) {
                    tools.提醒弹窗("指定的表【"+tb+"】不在指定的库【"+db+"】里");
                    return false;
                }
                flag =true;
                break;
            }
        }
        if(!flag){
            tools.提醒弹窗("指定的数据库【"+db+"】不存在");
            return false;
        }
        return true;
    }
    /*
     *  作者：icefield
     *  说明：往信息框更新信息
     */
    public void updataStatus(String msg){
        if (Platform.isFxApplicationThread()){
            信息框.appendText(msg);
        }else{
            Platform.runLater(()->{信息框.appendText(msg);});
        }
    }

    public TextArea get信息框(){
        return 信息框;
    }

    public static ice.controller.单一 get单一() {
        return 单一;
    }

}
